/* 
 * CpfValidator.java
 * 
 * Data de criação: 05/04/2010
 * 
 * CORPORATIVO - MTE. 
 *
 */
package br.com.o2solutions.util.validator;

import java.util.ArrayList;
import java.util.List;

import org.springframework.util.Assert;

import br.com.o2solutions.util.exception.validator.CpfValidatorException;
import br.com.o2solutions.util.lang.StringUtil;

/**
 * Classe Utilitaria para validação e operacões relacionadas ao CPF.
 * 
 * @author osvaldeir
 * @since 05/04/2010
 * 
 */
public class CpfValidator {

	private static List<String> invalidCpf = new ArrayList<String>();

	static {
		invalidCpf.add("11111111111");
	}

	/**
	 * Remove toda a máscara do CPF. Caso seja informado um CPF inválido é
	 * lancada uma exceção.
	 * 
	 * @param cpf
	 * @return String
	 */
	public static String unmask(String cpf) {
		Assert.hasText(cpf);
		cpf = StringUtil.deleteAny(cpf, ".");
		cpf = StringUtil.deleteAny(cpf, "-");
		return cpf;
	}

	/**
	 * Realiza a validacao de um cpf quanto a validacao do seu valor.
	 * 
	 * @param cpf
	 * @throws CpfValidatorException
	 *             Caso o CPF for inválido.
	 */
	public static void validate(String cpf) throws CpfValidatorException {
		try {
			Assert.hasText(cpf);
			Assert.state(cpf.length() >= 11);
			Assert.isTrue(!invalidCpf.contains(unmask(cpf)));
			Assert.state(isValid(unmask(cpf)));
		} catch (Throwable e) {
			throw new CpfValidatorException();
		}
	}

	/**
	 * Realiza a validação do CPF.
	 * 
	 * @param strCPF
	 *            número de CPF a ser validado
	 * @return true se o CPF é válido e false se não é válido
	 */
	static public boolean isValid(String strCpf) {
		int d1, d2;
		int digito1, digito2, resto;
		int digitoCPF;
		String nDigResult;

		d1 = d2 = 0;
		digito1 = digito2 = resto = 0;

		for (int nCount = 1; nCount < strCpf.length() - 1; nCount++) {
			digitoCPF = Integer.valueOf(strCpf.substring(nCount - 1, nCount))
					.intValue();
			// multiplique a ultima casa por 2 a seguinte por 3 a seguinte por 4
			// e assim por diante.
			d1 = d1 + (11 - nCount) * digitoCPF;
			// para o segundo digito repita o procedimento incluindo o primeiro
			// digito calculado no passo anterior.
			d2 = d2 + (12 - nCount) * digitoCPF;
		}
		;

		// Primeiro resto da divisão por 11.
		resto = (d1 % 11);
		// Se o resultado for 0 ou 1 o digito é 0 caso contrário o digito é 11
		// menos o resultado anterior.
		if (resto < 2)
			digito1 = 0;
		else
			digito1 = 11 - resto;

		d2 += 2 * digito1;
		// Segundo resto da divisão por 11.
		resto = (d2 % 11);
		// Se o resultado for 0 ou 1 o digito é 0 caso contrário o digito é 11
		// menos o resultado anterior.
		if (resto < 2)
			digito2 = 0;
		else
			digito2 = 11 - resto;
		// Digito verificador do CPF que está sendo validado.
		String nDigVerific = strCpf.substring(strCpf.length() - 2, strCpf
				.length());
		// Concatenando o primeiro resto com o segundo.
		nDigResult = String.valueOf(digito1) + String.valueOf(digito2);
		// comparar o digito verificador do cpf com o primeiro resto + o segundo
		// resto.
		return nDigVerific.equals(nDigResult);
	}

}
